/**
 * 性能和错误处理端到端测试
 * 测试游戏性能、错误恢复和边界情况
 */
describe('性能和错误处理测试', () => {
  beforeEach(() => {
    cy.visit('/')
  })

  describe('性能测试', () => {
    it('应该在合理时间内加载', () => {
      // 测量页面加载时间
      cy.window().then((win) => {
        const loadTime = win.performance.timing.loadEventEnd - win.performance.timing.navigationStart
        expect(loadTime).to.be.lessThan(5000) // 5秒内加载完成
      })
    })

    it('应该保持稳定的帧率', () => {
      cy.startNewGame()
      cy.selectCharacter('default')
      
      // 监控帧率
      let frameCount = 0
      const startTime = Date.now()
      
      cy.window().then((win) => {
        const measureFPS = () => {
          frameCount++
          if (Date.now() - startTime < 5000) { // 测试5秒
            win.requestAnimationFrame(measureFPS)
          } else {
            const fps = frameCount / 5
            expect(fps).to.be.greaterThan(30) // 至少30FPS
          }
        }
        win.requestAnimationFrame(measureFPS)
      })
      
      // 执行一些游戏操作
      cy.gameAction('jump')
      cy.wait(1000)
      cy.gameAction('slide')
      cy.wait(1000)
      cy.gameAction('left')
      cy.wait(1000)
      cy.gameAction('right')
      
      cy.wait(5000) // 等待性能测试完成
    })

    it('应该有效管理内存使用', () => {
      cy.startNewGame()
      cy.selectCharacter('default')
      
      // 获取初始内存使用
      cy.window().then((win) => {
        if (win.performance.memory) {
          const initialMemory = win.performance.memory.usedJSHeapSize
          
          // 执行大量操作
          for (let i = 0; i < 100; i++) {
            cy.gameAction('jump')
            cy.wait(50)
          }
          
          cy.wait(2000)
          
          // 检查内存增长
          const finalMemory = win.performance.memory.usedJSHeapSize
          const memoryIncrease = finalMemory - initialMemory
          
          // 内存增长应该在合理范围内（小于50MB）
          expect(memoryIncrease).to.be.lessThan(50 * 1024 * 1024)
        }
      })
    })

    it('应该在低性能设备上降级', () => {
      // 模拟低性能设备
      cy.window().then((win) => {
        // 模拟慢速设备
        Object.defineProperty(win.navigator, 'hardwareConcurrency', {
          value: 2,
          writable: false
        })
        
        // 模拟低内存
        if (win.navigator.deviceMemory) {
          Object.defineProperty(win.navigator, 'deviceMemory', {
            value: 2,
            writable: false
          })
        }
      })
      
      cy.reload()
      cy.startNewGame()
      cy.selectCharacter('default')
      
      // 验证性能优化启用
      cy.get('[data-cy="performance-mode"]').should('exist')
      cy.window().its('gameStore').then((store) => {
        expect(store.settings.performanceMode).to.be.true
      })
    })

    it('应该优化资源加载', () => {
      // 监控网络请求
      cy.intercept('**/*.{png,jpg,jpeg,gif,webp}', (req) => {
        req.reply((res) => {
          expect(res.headers['cache-control']).to.exist
          return res
        })
      }).as('imageRequests')
      
      cy.intercept('**/*.{mp3,ogg,wav}', (req) => {
        req.reply((res) => {
          expect(res.headers['cache-control']).to.exist
          return res
        })
      }).as('audioRequests')
      
      cy.reload()
      cy.startNewGame()
      cy.selectCharacter('default')
      
      // 验证资源缓存
      cy.wait('@imageRequests')
      cy.wait('@audioRequests')
    })
  })

  describe('错误处理测试', () => {
    it('应该处理Canvas渲染错误', () => {
      // 模拟Canvas错误
      cy.window().then((win) => {
        const originalGetContext = win.HTMLCanvasElement.prototype.getContext
        win.HTMLCanvasElement.prototype.getContext = () => null
        
        cy.startNewGame()
        cy.selectCharacter('default')
        
        // 验证降级到CSS渲染
        cy.get('[data-cy="css-fallback-mode"]').should('be.visible')
        cy.get('[data-cy="error-notification"]').should('contain', '渲染模式已切换')
        
        // 恢复原始方法
        win.HTMLCanvasElement.prototype.getContext = originalGetContext
      })
    })

    it('应该处理音频加载失败', () => {
      // 拦截音频请求并返回错误
      cy.intercept('**/*.{mp3,ogg,wav}', { statusCode: 404 }).as('audioError')
      
      cy.reload()
      cy.startNewGame()
      cy.selectCharacter('default')
      
      // 验证静音模式启用
      cy.get('[data-cy="audio-error-notification"]').should('be.visible')
      cy.window().its('gameStore').then((store) => {
        expect(store.audioManager.silentMode).to.be.true
      })
    })

    it('应该处理存储访问错误', () => {
      // 模拟localStorage不可用
      cy.window().then((win) => {
        Object.defineProperty(win, 'localStorage', {
          value: {
            getItem: () => { throw new Error('Storage not available') },
            setItem: () => { throw new Error('Storage not available') },
            removeItem: () => { throw new Error('Storage not available') }
          },
          writable: false
        })
      })
      
      cy.reload()
      cy.startNewGame()
      cy.selectCharacter('default')
      
      // 验证内存存储模式
      cy.get('[data-cy="storage-error-notification"]').should('be.visible')
      cy.window().its('gameStore').then((store) => {
        expect(store.storageManager.memoryMode).to.be.true
      })
    })

    it('应该处理网络连接问题', () => {
      // 模拟网络离线
      cy.window().then((win) => {
        Object.defineProperty(win.navigator, 'onLine', {
          value: false,
          writable: false
        })
        
        win.dispatchEvent(new Event('offline'))
      })
      
      // 验证离线模式
      cy.get('[data-cy="offline-notification"]').should('be.visible')
      cy.get('[data-cy="offline-mode-indicator"]').should('be.visible')
    })

    it('应该处理JavaScript运行时错误', () => {
      // 监听未捕获的错误
      cy.window().then((win) => {
        win.addEventListener('error', (event) => {
          // 验证错误被正确处理
          expect(event.error).to.exist
        })
        
        // 触发一个错误
        win.setTimeout(() => {
          throw new Error('Test runtime error')
        }, 100)
      })
      
      cy.wait(500)
      
      // 验证错误恢复
      cy.get('[data-cy="error-boundary"]').should('be.visible')
      cy.get('[data-cy="error-recovery-btn"]').click()
      cy.get('[data-cy="main-menu"]').should('be.visible')
    })

    it('应该处理内存不足情况', () => {
      // 模拟内存不足
      cy.window().then((win) => {
        const originalRequestAnimationFrame = win.requestAnimationFrame
        let frameCount = 0
        
        win.requestAnimationFrame = (callback) => {
          frameCount++
          if (frameCount > 1000) {
            // 模拟内存不足
            throw new Error('Out of memory')
          }
          return originalRequestAnimationFrame(callback)
        }
      })
      
      cy.startNewGame()
      cy.selectCharacter('default')
      
      // 等待错误触发
      cy.wait(5000)
      
      // 验证内存优化模式
      cy.get('[data-cy="memory-optimization-notification"]').should('be.visible')
    })
  })

  describe('边界情况测试', () => {
    it('应该处理极快的输入', () => {
      cy.startNewGame()
      cy.selectCharacter('default')
      
      // 快速连续输入
      for (let i = 0; i < 50; i++) {
        cy.get('body').type(' ', { delay: 0 })
      }
      
      // 验证游戏仍然响应
      cy.get('[data-cy="game-canvas"]').should('be.visible')
      cy.checkGameStatus('playing')
    })

    it('应该处理长时间游戏会话', () => {
      cy.startNewGame()
      cy.selectCharacter('default')
      
      // 模拟长时间游戏
      cy.window().then((win) => {
        // 快进游戏时间
        win.gameStore.gameTime = 3600000 // 1小时
        win.dispatchEvent(new CustomEvent('long-session-detected'))
      })
      
      // 验证休息提醒
      cy.get('[data-cy="break-reminder"]').should('be.visible')
    })

    it('应该处理窗口失焦和恢复', () => {
      cy.startNewGame()
      cy.selectCharacter('default')
      
      // 模拟窗口失焦
      cy.window().then((win) => {
        win.dispatchEvent(new Event('blur'))
      })
      
      // 验证游戏自动暂停
      cy.checkGameStatus('paused')
      
      // 模拟窗口恢复焦点
      cy.window().then((win) => {
        win.dispatchEvent(new Event('focus'))
      })
      
      // 验证暂停状态保持
      cy.get('[data-cy="focus-resume-prompt"]').should('be.visible')
    })

    it('应该处理浏览器标签页切换', () => {
      cy.startNewGame()
      cy.selectCharacter('default')
      
      // 模拟标签页隐藏
      cy.window().then((win) => {
        Object.defineProperty(win.document, 'hidden', {
          value: true,
          writable: true
        })
        win.document.dispatchEvent(new Event('visibilitychange'))
      })
      
      // 验证游戏暂停
      cy.checkGameStatus('paused')
      
      // 模拟标签页显示
      cy.window().then((win) => {
        Object.defineProperty(win.document, 'hidden', {
          value: false,
          writable: true
        })
        win.document.dispatchEvent(new Event('visibilitychange'))
      })
      
      // 验证恢复提示
      cy.get('[data-cy="tab-resume-prompt"]').should('be.visible')
    })

    it('应该处理极端屏幕尺寸', () => {
      // 测试极小屏幕
      cy.viewport(320, 240)
      cy.reload()
      
      // 验证UI适配
      cy.get('[data-cy="game-container"]').should('have.class', 'ultra-small')
      cy.get('[data-cy="ui-elements"]').should('have.class', 'compact')
      
      // 测试极大屏幕
      cy.viewport(3840, 2160)
      cy.reload()
      
      // 验证UI适配
      cy.get('[data-cy="game-container"]').should('have.class', 'ultra-wide')
    })
  })

  describe('恢复机制测试', () => {
    it('应该能够从错误状态恢复', () => {
      // 触发错误
      cy.window().then((win) => {
        win.dispatchEvent(new CustomEvent('critical-error'))
      })
      
      // 验证错误界面
      cy.get('[data-cy="error-screen"]').should('be.visible')
      
      // 尝试恢复
      cy.get('[data-cy="retry-btn"]').click()
      
      // 验证恢复成功
      cy.get('[data-cy="main-menu"]').should('be.visible')
    })

    it('应该保存游戏状态以便恢复', () => {
      cy.startNewGame()
      cy.selectCharacter('default')
      
      // 获得一些分数
      cy.window().then((win) => {
        win.gameStore.score = 500
      })
      
      // 模拟意外关闭
      cy.window().then((win) => {
        win.dispatchEvent(new Event('beforeunload'))
      })
      
      // 重新加载页面
      cy.reload()
      
      // 验证恢复提示
      cy.get('[data-cy="recovery-prompt"]').should('be.visible')
      cy.get('[data-cy="recover-game-btn"]').click()
      
      // 验证游戏状态恢复
      cy.get('[data-cy="score-display"]').should('contain', '500')
    })
  })
})